/**
 * @file JwtUtils.h
 * @brief JWT工具类，提供JWT令牌的生成、验证、解析和管理功能
 * @author CloudLinker
 * @date 2023-06-14
 */

#pragma once

#include "../CLink_Export.h"
#include <string>
#include <map>
#include <chrono>
#include <vector>
#include <set>
#include <optional>
#include <Poco/JWT/Token.h>
#include <Poco/JWT/Signer.h>

namespace CLink
{
namespace Utils
{

/**
 * @class JwtUtils
 * @brief JWT工具类，提供JWT令牌的生成、验证、解析和管理功能
 */
class CLINK_CLASS JwtUtils
{
public:
    /**
     * @brief 令牌验证选项结构体
     */
    struct VerificationOptions
    {
        bool checkExpiration;                          ///< 是否检查过期时间
        bool checkIssuer;                              ///< 是否检查发行者
        bool checkNotBefore;                           ///< 是否检查生效时间
        std::vector<std::string> allowedAlgorithms;    ///< 允许的签名算法
        
        VerificationOptions() 
            : checkExpiration(true), 
              checkIssuer(true), 
              checkNotBefore(true), 
              allowedAlgorithms({"HS256"}) {}
    };

    /**
     * @brief 令牌生成选项结构体
     */
    struct GenerationOptions
    {
        std::string algorithm;                      ///< 签名算法
        std::optional<std::string> jwtId;           ///< 令牌ID
        std::optional<int64_t> notBefore;           ///< 生效时间（Unix时间戳）
        std::map<std::string, std::string> headers; ///< 自定义头部
        
        GenerationOptions() 
            : algorithm("HS256") {}
    };

    /**
     * @brief 构造函数
     * @param secret JWT签名密钥
     * @param issuer 令牌发行者
     * @param expiresIn 令牌有效期（秒）
     */
    JwtUtils(const std::string &secret, const std::string &issuer, int expiresIn = 3600);

    /**
     * @brief 生成JWT令牌
     * @param subject 令牌主题（通常是用户ID）
     * @param claims 自定义声明
     * @param options 令牌生成选项
     * @return 生成的JWT令牌字符串
     * @throw JwtException 当令牌生成失败时抛出异常
     */
    std::string generateToken(
        const std::string &subject,
        const std::map<std::string, std::string> &claims = {},
        const GenerationOptions &options = GenerationOptions{});

    /**
     * @brief 验证JWT令牌
     * @param token JWT令牌字符串
     * @param options 验证选项
     * @return 令牌是否有效
     */
    bool verifyToken(const std::string &token, const VerificationOptions &options = VerificationOptions{});

    /**
     * @brief 从JWT令牌中获取声明值
     * @param token JWT令牌字符串
     * @param claimName 声明名称
     * @return 声明值，如果令牌无效或声明不存在则返回空字符串
     */
    std::string getClaim(const std::string &token, const std::string &claimName);

    /**
     * @brief 从JWT令牌中获取所有声明
     * @param token JWT令牌字符串
     * @return 所有声明的键值对，如果令牌无效则返回空映射
     */
    std::map<std::string, std::string> getAllClaims(const std::string &token);

    /**
     * @brief 检查令牌是否过期
     * @param token JWT令牌字符串
     * @return 令牌是否已过期
     */
    bool isTokenExpired(const std::string &token);

    /**
     * @brief 获取令牌过期时间
     * @param token JWT令牌字符串
     * @return 过期时间戳（秒），如果令牌无效则返回0
     */
    Poco::Timestamp getExpirationTime(const std::string &token);

    /**
     * @brief 刷新JWT令牌
     * @param token 原JWT令牌字符串
     * @param additionalClaims 要添加或更新的声明
     * @return 新的JWT令牌字符串
     * @throw JwtException 当令牌无效或刷新失败时抛出异常
     */
    std::string refreshToken(
        const std::string &token,
        const std::map<std::string, std::string> &additionalClaims = {});

    /**
     * @brief 将令牌加入黑名单
     * @param token JWT令牌字符串
     * @param reason 可选的加入黑名单原因
     * @return 操作是否成功
     */
    bool blacklistToken(const std::string &token, const std::string &reason = "");

    /**
     * @brief 检查令牌是否在黑名单中
     * @param token JWT令牌字符串
     * @return 是否在黑名单中
     */
    bool isTokenBlacklisted(const std::string &token);

    /**
     * @brief 从黑名单中移除令牌
     * @param token JWT令牌字符串
     * @return 操作是否成功
     */
    bool removeFromBlacklist(const std::string &token);

    /**
     * @brief 获取令牌的签发时间
     * @param token JWT令牌字符串
     * @return 签发时间戳（秒），如果令牌无效则返回0
     */
    Poco::Timestamp getIssuedAt(const std::string &token);

    /**
     * @brief 获取令牌的生效时间
     * @param token JWT令牌字符串
     * @return 生效时间戳（秒），如果令牌无效或未设置则返回0
     */
    Poco::Timestamp getNotBefore(const std::string &token);

    /**
     * @brief 获取令牌ID
     * @param token JWT令牌字符串
     * @return 令牌ID，如果令牌无效或未设置则返回空字符串
     */
    std::string getTokenId(const std::string &token);

    /**
     * @brief 获取令牌的签名算法
     * @param token JWT令牌字符串
     * @return 签名算法名称，如果令牌无效则返回空字符串
     */
    std::string getAlgorithm(const std::string &token);

    /**
     * @brief 检查令牌是否为空或无效
     * @param token JWT令牌字符串
     * @return 如果令牌为空字符串、格式不正确或无法解析则返回true，否则返回false
     */
    bool isEmptyToken(const std::string &token);

    /**
     * @brief 设置默认的令牌有效期
     * @param expiresIn 有效期（秒）
     */
    void setDefaultExpiresIn(int expiresIn);

    /**
     * @brief 设置默认的验证选项
     * @param options 验证选项
     */
    void setDefaultVerificationOptions(const VerificationOptions &options);

private:
    std::string secret_;                             ///< JWT签名密钥
    std::string issuer_;                             ///< 令牌发行者
    int expiresIn_;                                  ///< 令牌有效期（秒）
    std::set<std::string> blacklist_;                ///< 令牌黑名单
    VerificationOptions defaultVerificationOptions_; ///< 默认验证选项
    std::string algorithm{"HS256"};                  ///< 默认签名算法

    /**
     * @brief 解析JWT令牌
     * @param token JWT令牌字符串
     * @return Poco::JWT::Token对象，如果解析失败则返回空对象
     */
    Poco::JWT::Token parseToken(const std::string &token);

    /**
     * @brief 验证令牌签名
     * @param token JWT令牌字符串
     * @param algorithm 签名算法
     * @return 签名是否有效
     */
    bool verifySignature(const std::string &token, const std::string &algorithm);

    /**
     * @brief 清理过期的黑名单条目
     */
    void cleanupBlacklist();
};

} // namespace Utils
} // namespace CLink